﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Basic.第一章;
using Basic.第二章.SelfConfig;

namespace Basic.Part2
{
    public interface IConfigurationSource
    {
        /// <summary>
        /// ConfigurationBroker可以用过回调该方法，加载每个配置节组需要缓冲配置的对象
        /// </summary>
        void Load();
    }

    public static class SelfConfigurationBroker
    {
        static SelfConfigurationBroker()
        {
            var config = (ItemsSection)ConfigurationManager.GetSection("custom/items");
            Cache = new GenericCache<Type, object>();
            foreach (var item in config.Items)
            {
                var interfaceType = Type.GetType(((ItemElement)item).Source);
                var modelType = Type.GetType(((ItemElement)item).Target);
                if (interfaceType == null || modelType == null) return;
                if (interfaceType.IsAssignableFrom(modelType))
                {
                    Cache.Add(interfaceType, Activator.CreateInstance(modelType));
                }
            }
        }

        #region Fields
        /// <summary>
        /// 用于保存所有需要登记的通过配置获取的类型实体，使用线程安全的内存缓冲对象
        /// </summary>
        private static readonly GenericCache<Type, object> Cache;


        /// <summary>
        /// 各配置项将客户程序需要使用的配置对象通过该方法缓存
        /// </summary>
        /// <param name="type">配置对象的类型</param>
        /// <param name="item">实际的配置对象实例</param>
        public static void Add(Type type, object item)
        {
            if ((type == null) || (item == null)) throw new NullReferenceException();
            Cache.Add(type, item);
        }

        public static void Add(KeyValuePair<Type, object> item)
        {
            Add(item.Key, item.Value);
        }

        public static void Add(object item)
        {
            Add(item.GetType(), item);
        }

        /// <summary>
        /// 获取缓冲的配置对象
        /// </summary>
        /// <typeparam name="T">配置对象的类型</typeparam>
        /// <returns>实际的配置独享实例</returns>
        public static T GetConfigurationObject<T>() where T : class
        {
            if (Cache.Count <= 0) return null;
            object result;
            if (!Cache.TryGetValue(typeof(T), out result)) return null;
            return (T)result;
        }
        #endregion
    }



    /// <summary>
    /// 集中的配置文件信息访问Broker
    /// </summary>
    public static class ConfigurationBroker
    {
        #region Fields
        /// <summary>
        /// 用于保存所有需要登记的通过配置获取的类型实体，使用线程安全的内存缓冲对象
        /// </summary>
        private static readonly GenericCache<Type, object> Cache;

        static ConfigurationBroker()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            Cache = new GenericCache<Type, object>();
            //查找自定义的IconfigurationSource配置节组，并调用Load方法加载配置对象
            foreach (ConfigurationSectionGroup group in config.SectionGroups)
            {
                var t = typeof(IConfigurationSource);
                var groupType = group.GetType();
                if (!t.IsAssignableFrom(groupType)) continue;
                var trans = ((IConfigurationSource)group);
                trans.Load();
            }
        }

        /// <summary>
        /// 各配置项将客户程序需要使用的配置对象通过该方法缓存
        /// </summary>
        /// <param name="type">配置对象的类型</param>
        /// <param name="item">实际的配置对象实例</param>
        public static void Add(Type type, object item)
        {
            if ((type == null) || (item == null)) throw new NullReferenceException();
            Cache.Add(type, item);
        }

        public static void Add(KeyValuePair<Type, object> item)
        {
            Add(item.Key, item.Value);
        }

        public static void Add(object item)
        {
            Add(item.GetType(), item);
        }

        /// <summary>
        /// 获取缓冲的配置对象
        /// </summary>
        /// <typeparam name="T">配置对象的类型</typeparam>
        /// <returns>实际的配置独享实例</returns>
        public static T GetConfigurationObject<T>() where T : class
        {
            if (Cache.Count <= 0) return null;
            object result;
            if (!Cache.TryGetValue(typeof(T), out result)) return null;
            return (T)result;
        }
        #endregion
    }
}
